package com.heima.schedule.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.heima.common.constants.ScheduleConstants;
import com.heima.common.redis.CacheService;
import com.heima.model.schedule.dtos.Task;
import com.heima.model.schedule.pojos.Taskinfo;
import com.heima.model.schedule.pojos.TaskinfoLogs;
import com.heima.schedule.mapper.TaskInfoLogsMapper;
import com.heima.schedule.mapper.TaskInfoMapper;
import com.heima.schedule.service.TaskService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Set;

@Service
public class TaskServiceImpl implements TaskService {

    @Autowired
    private TaskInfoMapper taskInfoMapper;

    @Autowired
    private TaskInfoLogsMapper taskInfoLogsMapper;

    @Autowired
    private CacheService cacheService;

    /**
     * 添加定时任务
     * @param task
     */
    @Transactional
    public void saveTask(Task task) {
        // 将任务添加到taskinfo表中
        Taskinfo taskinfo = new Taskinfo();
        // 属性拷贝
        BeanUtils.copyProperties(task, taskinfo);
        // 设置执行时间
        taskinfo.setExecuteTime(new Date(task.getExecuteTime()));
        // 添加数据库
        taskInfoMapper.insert(taskinfo);
        // 设置任务ID
        task.setTaskId(taskinfo.getTaskId());

        // 将任务添加到taskinfo_logs表中（version = 1，status = 0）
        TaskinfoLogs taskinfoLogs = new TaskinfoLogs();
        // 属性拷贝
        BeanUtils.copyProperties(taskinfo, taskinfoLogs);
        // 设置属性
        taskinfoLogs.setVersion(ScheduleConstants.EXECUTED);
        taskinfoLogs.setStatus(ScheduleConstants.SCHEDULED);
        // 添加数据库
        taskInfoLogsMapper.insert(taskinfoLogs);

        // 判断任务是否过期，若到期则把任务放到list中
        if (System.currentTimeMillis() >= task.getExecuteTime()){
            String listKey = ScheduleConstants.TOPIC + task.getTaskType() + "_" + task.getPriority();
            cacheService.lLeftPush(listKey, JSON.toJSONString(task));
        }

        // 如果即将到期（大于当前系统时间，小于当前系统时间 + 5分钟），放到zset中
        if (task.getExecuteTime() > System.currentTimeMillis() && task.getExecuteTime() <= System.currentTimeMillis() + 1000 * 60 * 5){
            String setKey = ScheduleConstants.FUTURE + task.getTaskType() + "_" + task.getPriority();
            cacheService.zAdd(setKey, JSON.toJSONString(task), task.getExecuteTime());
        }


    }

    /**
     * 拉取到期的文章
     * @param taskType
     * @param priority
     * @return
     */
    @Transactional
    public Task pollTask(Integer taskType, Integer priority) {
        // 构建list集合的key
        String listKey = ScheduleConstants.TOPIC + taskType + "_" + priority;
        // 把key中第一条记录移除并返回
        String s = cacheService.lRightPop(listKey);
        if (StringUtils.isNotBlank(s)){
            Task task = JSON.parseObject(s, Task.class);
            // 将任务从taskinfo表删除
            taskInfoMapper.deleteById(task.getTaskId());
            // 将任务从taskinfo表中的任务状态改为已消费
            TaskinfoLogs taskinfoLogs = taskInfoLogsMapper.selectById(task.getTaskId());
            taskinfoLogs.setStatus(ScheduleConstants.EXECUTED);
            return task;
        }
        return null;
    }

    @Scheduled(cron = "*/5 * * * * ?")
    public void refreshZetToList(){
        Set<String> setKey = cacheService.scan(ScheduleConstants.FUTURE + "*");
        if (setKey.size() > 0 && setKey != null){
            for (String s : setKey) {
                String[] split = s.split("future_");
                // 获取zset对应的list的键
                String listKey = ScheduleConstants.TOPIC + split[1];
                // 从zset获取已过期的文章
                Set<String> strings = cacheService.zRangeByScore(s, 0, System.currentTimeMillis());
                // 如果文章已过期
                if (strings.size() > 0 && strings != null){
                    // 把文章移到list
                    cacheService.lLeftPushAll(listKey, strings);
                    // 把文章从zset剔除
                    cacheService.zRemove(s, strings);
                }
            }
        }
    }

    @Scheduled(cron = "0 */3 * * * ?")
    public void refreshDBToCache(){
        // 清空缓存
        Set<String> seKey = cacheService.scan(ScheduleConstants.FUTURE);
        Set<String> lisKey = cacheService.scan(ScheduleConstants.TOPIC);
        cacheService.delete(seKey);
        cacheService.delete(lisKey);
        // 查出taskinfo表的所有数据
        List<Taskinfo> taskinfos = taskInfoMapper.selectList(null);
        if (taskinfos.size() != 0 && taskinfos != null){
            for (Taskinfo taskinfo : taskinfos) {
                if (taskinfo.getExecuteTime().getTime() <= System.currentTimeMillis()){
                    String listKey = ScheduleConstants.TOPIC + taskinfo.getTaskType() + "_" + taskinfo.getPriority();
                    Task task = new Task();
                    BeanUtils.copyProperties(taskinfo, task);
                    task.setExecuteTime(taskinfo.getExecuteTime().getTime());
                    cacheService.lLeftPush(listKey, JSON.toJSONString(task));
                }
                if (taskinfo.getExecuteTime().getTime() > System.currentTimeMillis() && taskinfo.getExecuteTime().getTime() <= System.currentTimeMillis() + 1000 * 60 * 5){
                    String setKey = ScheduleConstants.FUTURE + taskinfo.getTaskType() + "_" + taskinfo.getPriority();
                    Task task = new Task();
                    BeanUtils.copyProperties(taskinfo, task);
                    task.setExecuteTime(taskinfo.getExecuteTime().getTime());
                    cacheService.zAdd(setKey, JSON.toJSONString(task), task.getExecuteTime());
                }
            }
        }
    }

}
